package Concorrentes;

import java.util.concurrent.ConcurrentLinkedQueue;

public class Balsa implements Runnable {

	private ConcurrentLinkedQueue<Carro> carrosEsperandoSentidoPraia;
	private ConcurrentLinkedQueue<Carro> carrosEsperandoSentidoSaoPaulo;
	private ConcurrentLinkedQueue<Carro> carrosLevando;
	
	private int posicao;
	private int direcao;
	private final int capacidade = 15;
	private final int velocidade = 40;
	private final int tempoMaximo = 100;
	private int tempoAtual;
	
	
	Balsa(){
		this.posicao = 0;
		this.direcao = 0;
		this.carrosEsperandoSentidoPraia = new ConcurrentLinkedQueue<Carro>();
		this.carrosEsperandoSentidoSaoPaulo = new ConcurrentLinkedQueue<Carro>();
		this.carrosLevando = new ConcurrentLinkedQueue<Carro>();
	}
	
	public void run() {
		while(true){
			atualiza();
			espera();
		}
	}
	
	private void espera() {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
		}
	}

	public synchronized void atualiza(){
		if(!podeSair()){
			tempoAtual++;
			poeCarroNaBalsa();
		} else if(!chegou()){
			atualizaPosicao();
		} else {
			System.out.println("Balsa chegou no seu destino. Desembarcando carros.");
			while(!vazia()){
				tiraCarroDaBalsa();
			}
		}
	}

	private synchronized boolean vazia() {
		if(carrosLevando.size() == 0) {
			direcao = 1-direcao;
			return true;
		}
		else return false;
	}

	private synchronized void tiraCarroDaBalsa() {
		Carro carro;
		carro = carrosLevando.poll();
		if(carro != null){
			Controlador.carroSaiuDaBalsa(carro);
		}
	}


	private synchronized void atualizaPosicao() {
		if(direcao == 0){
			if(posicao == 0){
				System.out.println("Balsa saindo da praia levando " + carrosLevando.size() + " carros");
			}
			posicao += velocidade;
		}
		else {
			if(posicao == 1000){
				System.out.println("Balsa saindo para a praia levando " + carrosLevando.size() + " carros");
			}
			posicao -= velocidade;
		}
	}

	private synchronized void poeCarroNaBalsa() {
		Carro carro = null;
		if(!cheia()){
			if(direcao == 0){
				carro = carrosEsperandoSentidoSaoPaulo.poll();
				if(carro != null){
					carrosLevando.add(carro);
				}
			} else if(direcao == 1) {
				carro = carrosEsperandoSentidoPraia.poll();
				if(carro != null){
					carrosLevando.add(carro);
				}
			}
		}
	}

	private synchronized boolean cheia() {
		if(carrosLevando.size() == capacidade) 
			return true;
		else 
			return false;
	}

	private synchronized boolean chegou() {
		//System.out.println("Posicao " + posicao + " direcao " + direcao);
		if((posicao >= 1000 && direcao == 0) || (posicao <= 0 && direcao == 1)){
			return true;
		}
		else return false;
	}

	private synchronized boolean podeSair() {
		if(!cheia())// && tempoAtual < tempoMaximo) 
			return false;
		else 
			return true;
	}

	public synchronized void addCarroNaFila(Carro carro, int dir) {
		if(dir == 0){
			carrosEsperandoSentidoSaoPaulo.add(carro);
		}
		else {
			carrosEsperandoSentidoPraia.add(carro);
		}
	}
}
